package com.chow.test;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class HttpEngine {
	private static class TrustAnyTrustManager implements X509TrustManager {

		public void checkClientTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}

		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[] {};
		}
	}

	private static class TrustAnyHostnameVerifier implements HostnameVerifier {
		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	}

	/************************************************************/

	private CookieManager cm;
	private HttpResponse rsp;

	/************************************************************/

	public CookieManager getCookieManager() {
		return this.cm;
	}

	public void setCookieManager(CookieManager cm) {
		this.cm = cm;
	}

	public HttpResponse getHttpResponse() {
		return this.rsp;
	}

	public int getResponseCode() throws IOException {
		return this.rsp.getResponseCode();
	}

	public String getResponseHtml() throws UnsupportedEncodingException,
			IOException {
		return this.rsp.getResponseHtml();
	}

	public String getHeaderField(String name) {
		return this.rsp.getHeaderField(name);
	}

	/************************************************************/

	public HttpEngine() {
		this(null);
	}

	public HttpEngine(CookieManager cm) {
		if (cm == null)
			cm = new CookieManager();
		this.cm = cm;
	}

	/************************************************************/

	public void post(String url, KVPair[] args, KVPair[] body) throws Exception {
		this.request("POST", url, args, body, "UTF-8", 30000);
	}

	public void post(String url, KVPair[] args, KVPair[] body,
			String urlEncode, int timeout) throws Exception {
		this.request("POST", url, args, body, urlEncode, timeout);
	}

	public void get(String url, KVPair[] args, KVPair[] body) throws Exception {
		this.request("GET", url, args, body, "UTF-8", 30000);
	}

	public void get(String url, KVPair[] args, KVPair[] body, String urlEncode,
			String inEncode, String outEncode, int timeout) throws Exception {
		this.request("GET", url, args, body, urlEncode, timeout);
	}

	private void request(String method, String url, KVPair[] args,
			KVPair[] body, String urlEncode, int timeout) throws Exception {

		if (urlEncode == null || urlEncode.trim().isEmpty())
			urlEncode = "UTF-8";

		URLConnection conn = new URL(url).openConnection();
		HttpURLConnection hconn = (HttpURLConnection) conn;

		// trust any certification
		if (url.toLowerCase().startsWith("https")) {
			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, new TrustManager[] { new TrustAnyTrustManager() },
					new java.security.SecureRandom());
			HttpsURLConnection hsconn = (HttpsURLConnection) hconn;
			hsconn.setSSLSocketFactory(sc.getSocketFactory());
			hsconn.setHostnameVerifier(new TrustAnyHostnameVerifier());
		}

		hconn.setConnectTimeout(timeout);

		if (args != null) {
			for (KVPair pair : args)
				hconn.setRequestProperty(pair.getKey(), pair.getVal());
		}

		this.cm.setCookies(hconn);
		boolean isPost = method.trim().equalsIgnoreCase("POST");
		if (isPost)
			hconn.setDoOutput(true);
		hconn.connect();

		// POST request body data
		if (isPost && body != null) {
			String data = "";
			for (KVPair pair : body) {
				data += pair.getKey() + "=";
				data += URLEncoder.encode(pair.getVal(), urlEncode) + "&";
			}
			if (!data.isEmpty()) {
				data = data.substring(0, data.length() - 1);
				hconn.getOutputStream().write(data.getBytes());
				hconn.getOutputStream().flush();
			}
		}
		this.cm.storeCookies(hconn);

		this.rsp = new HttpResponse(hconn);
	}
}
